const chokidar = require('chokidar');
const path = require('path');
const chalk = require('chalk');

class FileWatcher {
    constructor(config, ftpClient) {
        this.config = config;
        this.ftpClient = ftpClient;
        this.watchers = [];
        this.syncQueue = new Map();
        this.syncTimer = null;
    }

    start() {
        console.log(chalk.blue('启动文件监控...'));
        
        const watchPaths = [
            {
                local: this.config.localAddonPath,
                remote: this.config.remoteAddonPath,
                name: 'ThinkPHP插件'
            },
            {
                local: this.config.localAssetsPath,
                remote: this.config.remoteAssetsPath,
                name: '前端资源'
            }
        ];

        watchPaths.forEach(({ local, remote, name }) => {
            if (this.pathExists(local)) {
                this.watchDirectory(local, remote, name);
            } else {
                console.warn(chalk.yellow(`警告: ${name}目录不存在 - ${local}`));
            }
        });

        console.log(chalk.green('✓ 文件监控已启动，等待文件变化...'));
    }

    watchDirectory(localPath, remotePath, displayName) {
        const watcher = chokidar.watch(localPath, {
            ignored: this.getIgnorePatterns(),
            persistent: true,
            ignoreInitial: true,
            awaitWriteFinish: {
                stabilityThreshold: 300,
                pollInterval: 100
            }
        });

        watcher
            .on('add', (filePath) => this.handleFileChange('add', filePath, localPath, remotePath, displayName))
            .on('change', (filePath) => this.handleFileChange('change', filePath, localPath, remotePath, displayName))
            .on('unlink', (filePath) => this.handleFileChange('unlink', filePath, localPath, remotePath, displayName))
            .on('addDir', (dirPath) => this.handleDirChange('addDir', dirPath, localPath, remotePath, displayName))
            .on('unlinkDir', (dirPath) => this.handleDirChange('unlinkDir', dirPath, localPath, remotePath, displayName))
            .on('error', error => console.error(chalk.red(`监控错误 [${displayName}]:`, error)));

        this.watchers.push({
            watcher,
            localPath,
            remotePath,
            displayName
        });

        console.log(chalk.green(`✓ 开始监控 ${displayName}: ${localPath}`));
    }

    handleFileChange(event, filePath, localBasePath, remoteBasePath, displayName) {
        const relativePath = path.relative(localBasePath, filePath).replace(/\\/g, '/');
        const remotePath = remoteBasePath + '/' + relativePath;

        if (event === 'add' || event === 'change') {
            console.log(chalk.cyan(`[${displayName}] ${event === 'add' ? '新增' : '修改'}: ${relativePath}`));
            this.queueSync(filePath, remotePath, 'upload');
        } else if (event === 'unlink') {
            console.log(chalk.yellow(`[${displayName}] 删除: ${relativePath}`));
            this.queueSync(null, remotePath, 'delete');
        }
    }

    handleDirChange(event, dirPath, localBasePath, remoteBasePath, displayName) {
        const relativePath = path.relative(localBasePath, dirPath).replace(/\\/g, '/');
        
        if (event === 'addDir') {
            console.log(chalk.cyan(`[${displayName}] 新增目录: ${relativePath}`));
        } else if (event === 'unlinkDir') {
            console.log(chalk.yellow(`[${displayName}] 删除目录: ${relativePath}`));
        }
    }

    queueSync(localPath, remotePath, action) {
        const key = remotePath;
        
        if (this.syncQueue.has(key)) {
            clearTimeout(this.syncQueue.get(key).timer);
        }

        const timer = setTimeout(async () => {
            this.syncQueue.delete(key);
            await this.executeSync(localPath, remotePath, action);
        }, this.config.syncDelay || 1000);

        this.syncQueue.set(key, {
            localPath,
            remotePath,
            action,
            timer
        });
    }

    async executeSync(localPath, remotePath, action) {
        try {
            if (action === 'upload') {
                const success = await this.ftpClient.uploadFile(localPath, remotePath);
                if (!success) {
                    console.error(chalk.red(`同步失败 [${action}]: ${remotePath}`));
                    // 添加到重试队列
                    setTimeout(() => {
                        this.queueSync(localPath, remotePath, action);
                    }, 10000); // 10秒后重试
                }
            } else if (action === 'delete') {
                const success = await this.ftpClient.deleteFile(remotePath);
                if (!success) {
                    console.error(chalk.red(`删除失败: ${remotePath}`));
                }
            }
        } catch (error) {
            console.error(chalk.red(`同步失败 [${action}]:`, error.message));
        }
    }

    getIgnorePatterns() {
        const defaultPatterns = [
            '**/node_modules/**',
            '**/.git/**',
            '**/.DS_Store',
            '**/*.log',
            '**/*.tmp',
            '**/Thumbs.db'
        ];

        const configPatterns = this.config.excludePatterns || [];
        return [...defaultPatterns, ...configPatterns.map(p => `**/${p}`)];
    }

    pathExists(filePath) {
        const fs = require('fs');
        return fs.existsSync(filePath);
    }

    stop() {
        console.log(chalk.blue('停止文件监控...'));
        
        this.watchers.forEach(({ watcher, displayName }) => {
            watcher.close();
            console.log(chalk.yellow(`✓ 已停止监控 ${displayName}`));
        });
        
        this.syncQueue.forEach(({ timer }) => {
            clearTimeout(timer);
        });
        
        this.watchers = [];
        this.syncQueue.clear();
        
        console.log(chalk.green('✓ 文件监控已停止'));
    }
}

module.exports = FileWatcher;